home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
bit
/
src
/
dither.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
5KB
|
194 lines
/*
* $Id: dither.c,v 0.91 1994/02/20 00:53:05 zhao Pre-Release $
*
*. This file is part of BIT shareware package. After the two weeks of
* free evaluation period, you are encouraged (required) to register
* your copy for a small registration fee, which is $35 for personal use
* and $50 for commercial, government and institutional use.
*
* Copyright(c) 1993, 1994 by T.C. Zhao.
* All rights reserved.
*
* Permission to use, copy, and distribute this software in its entirety
* for non-commercial purposes is hereby granted, provided that the
* above shareware and copyright notices and this permission notice
* appear in all copies and their documentation.
*
* This software may be modified for your own use, but modified versions
* may not be distributed without prior consent of the author.
*
* This software is provided "as is" without expressed or implied
* warranty of any kind.
*
*.
*
* All gray to B&W dithering routines
*
*/
#if !defined(lint) && defined(F_ID)
char *id_dit = "$Id: dither.c,v 0.91 1994/02/20 00:53:05 zhao Pre-Release $";
#endif
#include "bit.h"
#include "lookup.h" /* defines dmatrix8 */
/******************* local variables ******************/
static int dither_threshold = -1;
static int bwmethod; /* dithering method */
/****************** local functions *****************/
/* All conversion function prototypes **/
typedef int (*bw_cnvt_t) (rgba_t **, int, int, bw_t **);
static int fs_dither(rgba_t **, int, int, bw_t **);
static int ordered_dither(rgba_t **, int, int, bw_t **);
/**************************************************************
* Text for option choices called by SetUP
**************************************************************/
const char *
bw_dither_string(void)
{
return "Ask|Floyd-Steinberg|Ordered8";
}
/* and its corresponding functions */
static bw_cnvt_t bwcnvt[] =
{
fs_dither, ordered_dither
};
/* control from Setup: Index corresponding to bw_dither_string */
extern int halftone_method;
/***********************************************************
* Master driver will call this routine before initiating
* the conversion via calling img_half_toning
************************************************************/
int
pre_bw(void)
{
static long mbwmethod = -1;
int method;
if (halftone_method > 0)
{
bwmethod = halftone_method - 1;
return 0;
}
/* choose interactively the dithering method */
if (mbwmethod < 0)
mbwmethod = defpup("HalftoneMethod %t|F-S|Ordered8|Cancel");
if ((method = dopup(mbwmethod)) <= 0 || method == 3)
return -1;
/* actual method */
bwmethod = method - 1;
return 0;
}
/*************************************************************
* Dispatcher, taking care of whatever =>GRAY conversion
*************************************************************/
int
img_half_toning(IPTR im)
{
bw_t **new;
CMPTR m = im->cmap;
/* convert to gray first. Note this recurses */
if (img_convert_type(im, T_GRAY) < 0)
return -1;
/* fake color map: 0 for black 1 for white */
im->colors = m->colors = 2;
m->ct[0][0] = m->ct[1][0] = m->ct[2][0] = 0;
m->ct[0][1] = m->ct[1][1] = m->ct[2][1] = PCMAXV;
new = get_mat(im->h, im->w, sizeof(bw_t));
if (bwcnvt[bwmethod] (im->mraster, im->h, im->w, new) < 0)
return -1;
return fill_image_struct(im, new, im->h, im->w, T_BW);
}
/*************************************************************
* Ordered dither. The input matrix MUST be in RGB(gray)
*************************************************************/
static int
ordered_dither(rgba_t **mat, int h, int w, bw_t **mm)
{
register rgba_t *ras;
register bw_t *m;
register short *dm;
register int i, j;
for (j = 0; j < h; j++)
{
dm = dmatrix8[j % 16];
for (i = 0, m = mm[j], ras = mat[j]; i < w; i++, ras++, m++)
*m = get_R(*ras) >= dm[i % 16];
}
return 0;
}
/*************************************************************
* Floyd-Steiberg
*************************************************************/
static int
fs_dither(rgba_t **mat, int h, int w, bw_t **mm)
{
register bw_t *m;
register rgba_t *ras;
register int *thisrow, *nextrow, dither2;
register int i, j;
int **tmp, err;
if (dither_threshold <= 0)
dither_threshold = PCMAXV / 2;
/* to preserve the errors on the edge, has to get one more row */
tmp = get_mat(h + 1, w, sizeof(**tmp));
ras = mat[0];
thisrow = tmp[0];
for (nextrow = thisrow + h * w; thisrow < nextrow; thisrow++, ras++)
*thisrow = get_R(*ras);
/*
* because we have the raster in a consecutive array, we got the edge
* errors right for free
*/
dither2 = PCMAXV;
for (i = 0; i < h; i++)
{
thisrow = tmp[i];
/* can't have it run to h 'cause nextrow[j+1] will be wrong */
if (i < h - 1)
nextrow = tmp[i + 1];
for (m = mm[i], j = 0; j < w; j++, m++)
{
err = thisrow[j] -
((*m = thisrow[j] >= dither_threshold) ? dither2 : 0);
thisrow[j + 1] += (err * 7) / 16;
nextrow[j - 1] += (err * 3) / 16;
nextrow[j] += (err * 5) / 16;
nextrow[j + 1] += err / 16;
}
}
free_mat(tmp);
return 0;
}